import store from '@/store'
import { login } from '@/api/user'
import { isArray } from '@/utils/validate'
import { baseURL, requestTimeout, contentType, successCode, statusName, messageName } from './config'
import instance from '@/utils/request'

let loadingInstance

let refreshToking = false

let requests = []

// 操作正常Code数组
const codeVerificationArray = isArray(successCode) ? [...successCode] : [...[successCode]]

const CODE_MESSAGE = {
  0: '未知错误',
  200: '服务器成功返回请求数据',
  201: '新建或修改数据成功',
  202: '一个请求已经进入后台排队(异步任务)',
  204: '删除数据成功',
  400: '发出信息有误',
  401: '用户没有权限(令牌失效、用户名、密码错误、登录过期)',
  402: '令牌过期',
  403: '用户得到授权，但是访问是被禁止的',
  404: '访问资源不存在',
  406: '请求格式不可得',
  410: '请求资源被永久删除，且不会被看到',
  500: '服务器发生错误',
  502: '网关错误',
  503: '服务不可用，服务器暂时过载或维护',
  504: '网关超时',
}

/**
 * @description 请求拦截器配置
 * @param config
 * @returns {any}
 */
const requestConf = config => {
  const apiVersion = config?.custom?.version || '' // 接口版本号，非必须
  const token = store.getters['user/accessToken']
  const tokenType = store.getters['user/tokenType']

  config.header['Authorization'] = `${tokenType} ${token}`
  config.header['Accept'] = `application/vnd.${apiVersion}+json;charset=utf-8`

  if (config?.custom?.loading) loadingInstance = uni.showLoading()
  return config
}

/**
 * @description 响应拦截器
 * @param config 请求配置
 * @param data response数据
 * @param statusCode HTTP status
 * @param statusText HTTP status text
 * @returns {Promise<*|*>}
 */
const handleData = async ({ config, data, tempFilePath, statusCode = 0, statusText }) => {
  if (loadingInstance) uni.hideLoading()
  // 若data.code存在，覆盖默认code
  let code = data && data[statusName] ? data[statusName] : statusCode
  // 若code属于操作正常code，则code修正为200
  if (codeVerificationArray.indexOf(code) + 1) code = 200
  switch (code) {
    case 200:
      return config.method == 'DOWNLOAD' ? tempFilePath : data
    case 900001:
      return Promise.reject(data)
    case 400001:
      uni.$u.func.showToast('请重新登录')
      break
    case 400004:
      return data
    case 400005:
      return await tryRefreshToken(config)
    case 400003:
      uni.$u.func.showToast('没有权限')
      break
  }
  // 异常处理
  // 若data.msg存在，覆盖默认提醒消息
  const errMsg = `${data && data[messageName] ? data[messageName] : CODE_MESSAGE[code] ? CODE_MESSAGE[code] : statusText}`
  if (!config?.custom?.noToast) {
    uni.$u.func.showToast({
      title: errMsg,
      duration: 2000,
    })
  }
  // 是否添加错误日志(与errorHandler钩子触发逻辑一致)
  // if (needErrorLog()) addErrorLog({ message: errMsg, stack: data, isRequest: true })
  return Promise.reject(data)
}

/**
 * @description  刷新令牌
 * @param config 过期请求配置
 * @returns {any} 返回结果
 */
const tryRefreshToken = async config => {
  const refreshToken = store.getters['user/refreshToken']
  if (!refreshToking) {
    refreshToking = true
    try {
      // const { data } = await login({ grant_type: 'refresh_token', refresh_token: refreshToken })
      // 刷新token接口
      if (data.accessToken) {
        store.setState('user', 'accessToken', data.accessToken)
        // 已经刷新了accessToken，将所有队列中的请求进行重试
        requests.forEach(cb => cb(data.accessToken))
        requests = []
        return instance(requestConf(config))
      }
    } catch (error) {
      console.error('refreshToken error =>', error)
    } finally {
      refreshToking = false
    }
  } else {
    return new Promise(resolve => {
      // 将resolve放进队列，用一个函数形式来保存，等token刷新后直接执行
      requests.push(() => {
        resolve(instance(requestConf(config)))
      })
    })
  }
}

/**
 * @description 初始化
 */
const initConf = () => ({
  baseURL,
  timeout: requestTimeout,
  header: {
    'Content-Type': contentType,
  },
})
module.exports = () => {
  // 初始化请求配置
  uni.$u.http.setConfig(initConf)
  // 请求拦截
  uni.$u.http.interceptors.request.use(requestConf, config => {
    // 可使用async await 做异步操作
    return Promise.reject(config)
  })
  // 响应拦截
  uni.$u.http.interceptors.response.use(
    response => handleData(response),
    error => {
      const { response = {} } = error
      return handleData(response)
    }
  )
}
